实际接触,认识到angularjs冰山一角;
表单是交互中最难的,超过动画;有太多不确定因素,包括验证,数据缓存,提交,更新样式/状态等。
angularjs:https://angularjs.org
angular:https://angular.io/
实际使用的angularjs版本:1.3.15。没有把文档lu一遍
https://code.angularjs.org/1.3.15/docs/api
一 基本
angularjs:MVC,双向数据绑定,依赖注入,指令 …
功能强大,尤其是和表单/数据 操作;
双向数据绑定表单提交时,需要注意提交成功后才可以更新视图
验证功能,自己做了处理;没有用三方
指令/过滤/element/函数 等都实用
没有实用路由功能
事件机制也没有研究,不像react等那么清楚
控制器和依赖注入
$scope,$http,$timeout等需要注入才可以使用,包括自定义的服务。
三种注入方式,上面最合适
$scope相当于作用域
没有实用嵌套,互相传递
$scope的方法:$scope.$apply(), $scope.$watch()
- $watch
- $http有三种方式的缓存可以利用
1
2
3
4.controller('controller', function($scope,$http,$timeout) {
// 数据缓存
$http.get('./db/quiz.php?act=get_quiz_report&author=' + encodeURIComponent($scope.oEditQuiz.FAuthor),{cache:true})
});
参考:
说说Angular $http service中的缓存
ular $http cache学习笔记
angular方法
copy,equals,forEach,element,…
isNumber,isObject没有用
forEach: 和ES5的参数,顺序不一样;如果不支持ES5,可以用ng
copy: 深度克隆
equals: 对象/数值的数值比较
element: jQ方式的dom操作1
2
3
4
5
6// jQuery Lite
angular.element('.table-headFixed_body .table tr').css({background:'#fff'});
// 可以在全局得到$scope绑定数据,控制台可以调试
var appElement = document.querySelector('[ng-controller=controller]');
goScope = angular.element(appElement).scope();
ng-class
对象时: 可以写表达式
className有特殊字符,比如-
需要加引号
结合css的优先级,样式切换的话,写一个ng-class(后定义的-优先级高,可以覆盖)就可以了1
2
3<div ng-class="{'quiz-bg-danger':quizQuestionView.correct===0}" class="quiz-bg-success">
{{ quizQuestionView.correct?'<?=$langmsg["1324"]?>':'<?=$langmsg["1325"]?>' }}<!-- Correct/Incorrect -->
</div>
下拉列表
可以给默认选项;设置选中项值的类型。
还可以获取之前选项,进行更改前的验证(如果需要的话)。1
2
3<select ng-change="doQuizQuestionType('{{quizQuestionEdit.type}}')" ng-model="quizQue stionEdit.type" ng-options="x.id as x.name for x in quizQuestion_type" class="form-control" name="edit_quizType" id="quizQuestion_type"></select>
<select ng-model="oEditQuiz.FQuizSetting.passingType" ng-options="x.id as x.name for x in quizSetting_types" name="quizSetting_type" id="quizSetting_type"></select>
1 | $scope.quizQuestion_type=[ |
参考:
AngularJs select绑定数字类型问题
angularjs – ng-change获取新值和原始值
单/多选框 切换
单/多选框用一个(ng-checked)时,双向数据绑定的时候有点抽风。
有时传回来的数组,切换问题的时候竟然变成了对象,然后就会导致没有绑定,视图中不会选中。
可能是因为:开始的时候用了一个input标签,数据绑定方式不是ng的方式。导致数据变为对象;而且,视图也不会根据数据做出正确的更新。
包括答题的时候,userAnswers是undefined的,需要手动换成一个数组。
最后:editMode,quizItem 中换成了两个标签,利用ng单/多选框的使用方式。
- editMode,quizItem还是分离了,取消了ng-check,利用ng原生的数据绑定方法。
但是需要为radio做未选中时数据为0,checkbox切换选中状态,添加了ng-click自己做控制。
包括没有点击时,默认为undefined的情况。 - dQuizReview 自定义样式,也抛弃了input的方式。可以用同一个元素(div/span等)表示了。样式/选中状态都可以灵活控制
- CHECK: editMode切换问题的时候,正确选项可能不会正确绑定
1 | <!-- dQuizItem --> |
不靠谱的ng-checked
以下内容,可能还是因为利用一个input标签导致切换的问题。
- 只有ng-checked
不靠谱啊:第一次进去是好,切换next/previous 单选框不能绑定,多选框少了第一个
有文章说,单选 ng-checked 还要判断 == ,然并卵对于radio的绑定,主要指定属性==true,也就是
<input id='sex' name="sex" type="radio" ng-model='sex' ng-checked="sex==true">男
而不是单纯的指定属性,如果单纯指定属性不返回属性的值
http://blog.csdn.net/u011127019/article/details/52556781 - 拆分成两个input 只有ng-model
根本没有绑定,即单/多选框不会选中(View中) - ng-model + ng-checked
和只有 ng-checked 的情况差不多
进阶
自定义过滤
ng-model中不能写过滤,需要自己写指令,结合指令的model配置项1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 angular.module('app', [])
.filter('seconds2str',function(){// cc from <docs.videojs.com/utils_format-time.js.html>
return function(seconds){
secodes=seconds<0?0:seconds;
var s=Math.floor(seconds %60);
var m=Math.floor(seconds / 60 %60);
var h=Math.floor(seconds / 3600);
if(isNaN(seconds)||seconds===Infinity){
h=m=s='-';
}
h=(h>0)?h+':':'';
m=((h>0&&m<10)?'0'+m:m)+':';
s=(s<10)?'0'+s:s;
return h+m+s;
}
})
// number过滤器
// <td>{{(quizStu.FTotalAwarded/quizStu.FTotalPoints)*100|number:0}}</td>
参考:
AngularJS - 如何将毫秒转换成xHours和yMins?
angular input输入框中使用filter格式化日期
自定义指令
可配置项还是很多的。return的方式,restrict/link/…,scope/element/…,注入的服务..
输出会在页面加载定义的时候输出一次;余下的输出只有在return 相应的函数/监听才会有输出
自定义指令功能很丰富
自定义指令,大小写:都是小写没问题;
定义时候有大写,html中使用时必须-
隔离大写,html中大写没用
获取焦点
1 | /** 两种方式 |
focus - 以 Angular 方式,设置元素焦点
深究AngularJS——如何获取input的焦点(自定义指令)
图片加载
1 | // console.log('redirecitv') |
参考:
详解Angularjs 如何自定义Img的ng-load 事件
angular实现图片预加载指令
AngularJS中如果ng-src 图片加载失败怎么办
滚动
参考:
1. angularJS-滚动到底部触发事件1
2
3
4
5
6
7
8
9
10
11
12
13// <div class="box" when-scrolled="loadMore()">
//滚动指令
pro.directive('whenScrolled', function() {
return function(scope, elm, attr) {
// 内层DIV的滚动加载
var raw = elm[0];
elm.bind('scroll', function() {
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
scope.$apply(attr.whenScrolled);
};
});
};
});
2. 通过AngularJS指令操作DOM同一个作者相同文章:Angular.JS通过指令操作DOM的方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41// 一个引入jQuery操作DOM的指令如下:
webApp.directive("detailTopStick", ["$timeout", "$window", function ($timeout, $window) {
return {
restrict: "A",
link: function (scope) {
$timeout(function () {
var navbar = $(".navbar-nav");
var navbarOffsetTop = navbar.offset().top;
var headerInfo = $(".header-info");
var headerInfoMarginBottom = parseInt(headerInfo.css("margin-bottom"));
var navbarHeight = parseInt(navbar.css("height"));
angular.element($window).bind("resize", function () { // 窗口绑定resize事件
navbar.css("width", headerInfo.width());
navbarOffsetTop = navbar.offset().top;
scope.$apply();
});
angular.element($window).bind("scroll", function () {
if ($window.scrollY > navbarOffsetTop) {
navbar.css("width", headerInfo.width());
navbar.addClass("detail-navbar-fix");
headerInfo.css("margin-bottom", headerInfoMarginBottom + navbarHeight);
}
else {
navbar.removeClass("detail-navbar-fix");
headerInfo.css("margin-bottom", headerInfoMarginBottom);
}
scope.$apply();
});
navbar.on("click", function () {
if ($window.scrollY > navbarOffsetTop) {
$window.scrollTo(0, navbarOffsetTop);
}
});
});
}
};
}]);
其它:
3. angular 自定义 scroll事件:
一个div里面包了很多个div,外面的div是可以的滚动的,而根据滚动到不同的区块时,每个内在的div要浮现出一块部分
4. Duang~简单实用的angular滚动列表特效(移动端):
做成滚动时固定,然后可以被下一个元素顶上去的效果
5. angularjs 的操作dom一般如何写在指令或者服务中?通过AngularJS指令操作DOM同一个作者相同文章:Angular.JS通过指令操作DOM的方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40// 一个引入jQuery操作DOM的指令如下:
webApp.directive("detailTopStick", ["$timeout", "$window", function ($timeout, $window) {
return {
restrict: "A",
link: function (scope) {
$timeout(function () {
var navbar = $(".navbar-nav");
var navbarOffsetTop = navbar.offset().top;
var headerInfo = $(".header-info");
var headerInfoMarginBottom = parseInt(headerInfo.css("margin-bottom"));
var navbarHeight = parseInt(navbar.css("height"));
angular.element($window).bind("resize", function () { // 窗口绑定resize事件
navbar.css("width", headerInfo.width());
navbarOffsetTop = navbar.offset().top;
scope.$apply();
});
angular.element($window).bind("scroll", function () {
if ($window.scrollY > navbarOffsetTop) {
navbar.css("width", headerInfo.width());
navbar.addClass("detail-navbar-fix");
headerInfo.css("margin-bottom", headerInfoMarginBottom + navbarHeight);
}
else {
navbar.removeClass("detail-navbar-fix");
headerInfo.css("margin-bottom", headerInfoMarginBottom);
}
scope.$apply();
});
navbar.on("click", function () {
if ($window.scrollY > navbarOffsetTop) {
$window.scrollTo(0, navbarOffsetTop);
}
});
});
}
};
}]);
ng-repeat + ng-model 数据筛选
$_PS: 没有实通1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<input type="text" placeholder="Search Records" ng-model="SearchText" />
<table>
<thead>
<tr>
<th> Name </th>
<th>Date of Birth </th>
<th>Address </th>
<th>Salary </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="employee in employees|filter :SearchText">
<td>{{employee.name }}</td>
<td>{{employee.dateOfBirth }}</td>
<td>{{employee.Address }}</td>
<td>{{employee.Salary }}</td>
<!-- <td>{{employee.Salary| currency }}</td> -->
</tr>
</tbody>
</table>
参考链接:
Search And MultiSearch In AngularJS
Simple search and filter with AngularJs
http://plnkr.co/edit/XklvXtc1AZpndjLvXrh8?p=preview
排序和serach
做了分页:一次取所有数据,拆分数据,单页显示
表格中是部分数据,利用 |filter:x
/|orderby:x
只是对表格中有的数据排序/过滤
自己过滤整个数据,根据新数据,制作新的分页
table分页
利用了第一种方式
参考一:无插件
Angular.js+Bootstrap实现表格分页
$_YX: Angular.js+Bootstrap实现表格分页
参考二:插件ng-pagination
angularjs+bootstrap自定义分页
基于Angularjs实现分页
详解angularjs结合pagination插件实现分页功能
表单
下面两个属于相同问题,button默认type为submit,更正type=button
。
button自动验证required
参考:
form表单下的button按钮会自动提交表单的问题error: “An invalid form control with name=’’ is not focusable.”。修改button类型后解决了
参考一:修改button:
An invalid form control with name=’file[]’ is not focusable.间接点击form表单的\出现的问题
An invalid form control with name=’’ is not focusable. WITHOUT ANY REQUIRED OR HIDDEN INPUTS参考二:form标签加 novalidate属性:
An invalid form control with name=’’ is not focusable
ng-repeat动态添加/删除dom
直接操作dom不明智。
参考:
angular.js 下如何动态插入删除dom节点
自动滚动到底部
操作dom性能是不是不好;有没有其他方式,比如指令。
操作dom的方法是原生js;非angular.element。
和监听window/element滚动事件操作dom不一样,是插入加载数据后自动滚动到底部,非监听滚动到底部加载数据。所以写了一个自动滚动到底部的函数。1
2
3
4
5
6
7
8
9
10
11
12
13$scope.scrollWindow=function(query){
dquiz('scroll window ...');
// var _el = document.getElementById(id);
var _el = document.querySelector(query);// $_MORE: 要不要换成angular.element
// dlog(_el.scrollTop);
if(_el.scrollHeight > _el.clientHeight){
_el.previousElementSibling.style.paddingRight='17px';
_el.scrollTop = _el.scrollHeight;
}else{
_el.previousElementSibling.style.paddingRight=0;
}
};
ISSUES
- input输入值后,再清空,绑定数据为undefined
注意事项:
radio/checkbox 绑定数据异常:数据绑定方式不规范(妄想一个dom利用两个不同的绑定方式);数据切换时,绑定数据为undefined